package com.dtzhejiang.social.supervision.risk.engine.core.task.tasklet;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dtzhejiang.social.supervision.risk.engine.common.domain.po.SpiderHospitalBusinessLicenseEntity;
import com.dtzhejiang.social.supervision.risk.engine.common.domain.po.SpiderHospitalEntity;
import com.dtzhejiang.social.supervision.risk.engine.common.domain.po.SpiderHospitalPracticeLicenseEntity;
import com.dtzhejiang.social.supervision.risk.engine.common.util.AliHttpUtils;
import com.dtzhejiang.social.supervision.risk.engine.common.util.LatitudeUtils;
import com.dtzhejiang.social.supervision.risk.engine.core.mapper.SpiderHospitalMapper;
import com.dtzhejiang.social.supervision.risk.engine.core.service.LicenseService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * Author: chenwenhao
 * Date: 9:38 2020/11/2
 * Content:店铺营业执照和执业许可证图片信息解析
 * @author cwh270990
 */
@Component
@Slf4j
public class LicenseAnalysisTask {

    @Resource
    private LicenseService licenseService;
    @Resource
    private SpiderHospitalMapper spiderHospitalMapper;

    private static final int LENGTH_256 = 256;
    private static final int LENGTH_0 = 0;
    private static final int LENGTH_50 = 50;
    private static final int LENGTH_32 = 32;

    private static final String BUSINESS_LICENSE_START = "{\"image\":\"";
    private static final String BUSINESS_LICENSE_END = "\"}";
    private static final String PRACTICE_LICENSE_START = "{\"image\":\"";
    private static final String PRACTICE_LICENSE_END = "\",\"configure\":{\"template_list\": [\n" +
            "                \"4b0ab2f5-0c05-436f-ad67-f1c9de54eee91604304626\"\n" +
            "                ]\n" +
            "               }  \n" +
            "}";

    /**
     * 每天凌晨一点
     */
    private static final String ANALYSIS_LICENSE_TIME = "0 0 1 * * ?";

    public static String SPECIAL_SYMBOL = ".*[)(*,.。:/~].*";
    public static String SPECIAL_SYMBOL_REPLACE = "[)(*,.。:/~]";

    public static String INSTITUTION_NAME_SYMBOL = ".*[#*/].*";
    public static String INSTITUTION_NAME_SYMBOL_REPLACE = "[#*/]";



    /**
     * 数字正则表达式-用来匹配
     */
    public static String DIGITAL_EXP = ".*\\d+.*";
    /**
     * 数字正则表达式-用来替换
     */
    public static String DIGITAL_EXP_REPLACE = "\\d+";

    /**
     * 中文正则表达式-用来匹配
     */
    public static String REGEX_CHINESE = ".*[\u4e00-\u9fa5].*";

    /**
     * 中文正则表达式-用来替换
     */
    public static String REGEX_CHINESE_REPLACE = "[\u4e00-\u9fa5]";

    public static final String FAIL_RECOGNIZE = "FailInRecognition";


    /**
     * 定时解析营业执照和执业许可证
     */
    @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000L, multiplier = 2))
    public void analysisLicense() {
        log.info("开始执行营业执照和执业许可证图片解析定时任务！");
        Date now = new Date();
        List<String> businessShopIds = licenseService.getAllShopIdsForBusinessLicense();
        List<String> practiceShopIds = licenseService.getAllShopIdsForPracticeLicense();
        QueryWrapper<SpiderHospitalEntity> wrapper = new QueryWrapper<>();
        wrapper.select("shop_id,business_card_url,permit_card_url").isNotNull("business_card_url").or().isNotNull("permit_card_url");
        List<SpiderHospitalEntity> spiderHospitalEntities = spiderHospitalMapper.selectList(wrapper);
        if (!CollectionUtils.isEmpty(spiderHospitalEntities)) {
            for (SpiderHospitalEntity spiderHospitalEntity : spiderHospitalEntities) {
                String shopId = spiderHospitalEntity.getShopId();
                if (!businessShopIds.contains(shopId)) {
                    if (StringUtils.isNotBlank(spiderHospitalEntity.getBusinessCardUrl())) {
                        String businessCardUrl = spiderHospitalEntity.getBusinessCardUrl().trim();
                        String businessCardJson = this.analysisBusinessCard(businessCardUrl);
                        log.info("店铺id为：" + shopId + "营业执照解析结果：" + businessCardJson);
                        this.saveBusinessCard(shopId, businessCardJson, now);
                    }

                }
                if (!practiceShopIds.contains(shopId)) {
                    if (StringUtils.isNotBlank(spiderHospitalEntity.getPermitCardUrl())) {
                        String practiceCardUrl = spiderHospitalEntity.getPermitCardUrl().trim();
                        String permitCardJson = this.analysisPermitCard(practiceCardUrl);
                        log.info("店铺id为：" + shopId + "执业许可证解析结果：" + permitCardJson);
                        this.savePermitCard(shopId, permitCardJson, now);
                    }
                }
            }
        }
    }

    /**
     * 调用阿里云OCR接口，解析营业执照图片信息
     * @return
     */
    private String analysisBusinessCard(String url) {
        String host = "https://dm-58.data.aliyun.com";
        String path = "/rest/160601/ocr/ocr_business_license.json";
        String method = "POST";
        String appcode = "772e5eff0f8a4924b2f48be7cc166be3";
        Map<String, String> headers = new HashMap<String, String>();
        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + appcode);
        //根据API的要求，定义相对应的Content-Type
        headers.put("Content-Type", "application/json; charset=UTF-8");
        Map<String, String> querys = new HashMap<String, String>(2);
        String bodys = BUSINESS_LICENSE_START + url + BUSINESS_LICENSE_END;
        String jsonResult = "";
        try {
            /**
             * 重要提示如下:
             * HttpUtils请从
             * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/src/main/java/com/aliyun/api/gateway/demo/util/HttpUtils.java
             * 下载
             *
             * 相应的依赖请参照
             * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/pom.xml
             */
            HttpResponse response = AliHttpUtils.doPost(host, path, method, headers, querys, bodys);
            if (response != null && response.getEntity() != null) {
                jsonResult = EntityUtils.toString(response.getEntity());
            }
        } catch (Exception e) {
            log.error("营业执照信息解析失败！图片url为：" + url, e);
        }
        return jsonResult;
    }

    public String analysisPermitCard(String url) {
        String host = "https://ocrdiy.market.alicloudapi.com";
        String path = "/api/predict/ocr_sdt";
        String method = "POST";
        String appcode = "772e5eff0f8a4924b2f48be7cc166be3";
        Map<String, String> headers = new HashMap<String, String>();
        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + appcode);
        //根据API的要求，定义相对应的Content-Type
        headers.put("Content-Type", "application/json; charset=UTF-8");
        Map<String, String> querys = new HashMap<String, String>();
        String bodys = PRACTICE_LICENSE_START + url + PRACTICE_LICENSE_END;
        String jsonResult = "";

        try {
            /**
             * 重要提示如下:
             * HttpUtils请从
             * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/src/main/java/com/aliyun/api/gateway/demo/util/HttpUtils.java
             * 下载
             *
             * 相应的依赖请参照
             * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/pom.xml
             */
            HttpResponse response = AliHttpUtils.doPost(host, path, method, headers, querys, bodys);
            if (response != null && response.getEntity() != null) {
                //获取response的body
                jsonResult = EntityUtils.toString(response.getEntity());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return jsonResult;
    }

    private void saveBusinessCard(String shopId, String json, Date now) {
        try {
            SpiderHospitalBusinessLicenseEntity businessLicense = new SpiderHospitalBusinessLicenseEntity();
            businessLicense.setShopId(shopId);
            if (!json.startsWith("Invalid Result")) {
                JSONObject jsonObject = JSON.parseObject(json);
                if (jsonObject != null) {
                    String person = jsonObject.getString("person");
                    person = formatPersonName(person);
                    businessLicense.setLegalPerson(person);
                    String address = jsonObject.getString("address");
                    address = formatAddress(address);
                    businessLicense.setAddress(address);
                    String engageScope = jsonObject.getString("business");
                    engageScope = filterFailRecognize(engageScope);
                    businessLicense.setEngageScope(engageScope);
                    String institutionName = jsonObject.getString("name");
                    institutionName = filterFailRecognize(institutionName);
                    businessLicense.setInstitutionName(institutionName);
                    String registerDate = jsonObject.getString("establish_date");
                    registerDate = filterFailRecognize(registerDate);
                    businessLicense.setRegisterDate(registerDate);
                    businessLicense.setShopId(shopId);
                    String uniCode = jsonObject.getString("reg_num");
                    uniCode = formatUnicode(uniCode);
                    businessLicense.setUniCode(uniCode);
                    String validDate = jsonObject.getString("valid_period");
                    businessLicense.setValidDate(validDate);
                    businessLicense.setGmtUpdate(now);
                    if (StringUtils.isNotBlank(businessLicense.getAddress())) {
                        fillBusinessLatitude(businessLicense);
                    }
                }
            }
            licenseService.saveOrUpdateBusinessLicense(businessLicense);
        } catch (Exception e) {
            log.error("营业执照信息入库失败! 店铺id为：" + shopId);
        }
    }

    private void savePermitCard(String shopId, String json, Date now) {
        try {
            JSONObject jsonObject = JSON.parseObject(json);
            if (jsonObject != null) {
                JSONObject items = (JSONObject) jsonObject.get("items");
                if (items != null) {
                    SpiderHospitalPracticeLicenseEntity practiceLicense = new SpiderHospitalPracticeLicenseEntity();
                    practiceLicense.setShopId(shopId);
                    String address = items.getString("address");
                    if (StringUtils.isNotBlank(address)) {
                        practiceLicense.setAddress(formatAddress(address));
                    }
                    String institutionName = items.getString("name");
                    institutionName = filterFailRecognize(institutionName);
                    if (StringUtils.isNotBlank(institutionName) && institutionName.length() > LENGTH_256) {
                        institutionName = institutionName.substring(LENGTH_0, LENGTH_256);
                    }
                    practiceLicense.setInstitutionName(institutionName);
                    String legalPerson = items.getString("person");
                    legalPerson = formatPersonName(legalPerson);
                    if (StringUtils.isNotBlank(legalPerson) && legalPerson.length() > LENGTH_32) {
                        legalPerson = legalPerson.substring(LENGTH_0, LENGTH_32);
                    }
                    practiceLicense.setLegalPerson(legalPerson);
                    String mainPerson = items.getString("main_person");
                    mainPerson = formatPersonName(mainPerson);
                    if (StringUtils.isNotBlank(mainPerson) && mainPerson.length() > LENGTH_32) {
                        mainPerson = mainPerson.substring(LENGTH_0, LENGTH_32);
                    }
                    practiceLicense.setMainPerson(mainPerson);
                    String medicalDepartments = items.getString("medical_departments");
                    medicalDepartments = filterFailRecognize(medicalDepartments);
                    practiceLicense.setMedicalDepartments(medicalDepartments);
                    String registerNo = items.getString("reg_num");
                    if (StringUtils.isNotBlank(registerNo) && registerNo.length() > LENGTH_50) {
                        registerNo = registerNo.substring(LENGTH_0, LENGTH_50);
                    }
                    registerNo = formatPracticeRegNo(registerNo);
                    practiceLicense.setRegisterNo(registerNo);
                    String validEndDate = items.getString("valid_end_date");
                    if (StringUtils.isNotBlank(validEndDate) && validEndDate.length() > LENGTH_50) {
                        validEndDate = validEndDate.substring(LENGTH_0, LENGTH_50);
                    }
                    validEndDate = filterFailRecognize(validEndDate);
                    practiceLicense.setValidEndDate(validEndDate);
                    String validStartDate = items.getString("valid_start_date");
                    if (StringUtils.isNotBlank(validStartDate) && validStartDate.length() > LENGTH_50) {
                        validStartDate = validStartDate.substring(LENGTH_0, LENGTH_50);
                    }
                    validStartDate = filterFailRecognize(validStartDate);
                    practiceLicense.setValidStartDate(validStartDate);
                    practiceLicense.setGmtUpdate(now);
                    if (StringUtils.isNotBlank(practiceLicense.getAddress())) {
                        fillPracticeLatitude(practiceLicense);
                    }
                    licenseService.saveOrUpdatePracticeLicense(practiceLicense);
                }
            }
        } catch (Exception e) {
            log.error("执业许可证信息入库失败! 店铺id为：" + shopId);
        }
    }

    public static void fillPracticeLatitude(SpiderHospitalPracticeLicenseEntity practiceLicense) {
        Map fromMap = LatitudeUtils.getGeocoderLatitude(practiceLicense.getAddress(), "");
        BigDecimal latitude = null;
        BigDecimal longitude = null;
        if (fromMap != null) {
            if (fromMap.get("lng") != null && fromMap.get("lat") != null) {
                longitude = new BigDecimal((String)fromMap.get("lng"));
                latitude = new BigDecimal((String) fromMap.get("lat"));
            }
        }
        practiceLicense.setLatitude(latitude);
        practiceLicense.setLongitude(longitude);
    }

    public static void fillBusinessLatitude(SpiderHospitalBusinessLicenseEntity businessLicense) {
        Map fromMap = LatitudeUtils.getGeocoderLatitude(businessLicense.getAddress(), "");
        BigDecimal latitude = null;
        BigDecimal longitude = null;
        if (fromMap != null) {
            if (fromMap.get("lng") != null && fromMap.get("lat") != null) {
                longitude = new BigDecimal((String)fromMap.get("lng"));
                latitude = new BigDecimal((String) fromMap.get("lat"));
            }
        }
        businessLicense.setLatitude(latitude);
        businessLicense.setLongitude(longitude);
    }


    /**
     * 清洗地址
     * @param address
     * @return
     */
    public static String formatAddress(String address) {
        if (StringUtils.isBlank(address)) {
            return "";
        }
        if (address.startsWith("地址") || address.startsWith("L.")) {
            address = address.substring(2);
        }
        if (address.startsWith("址:.")) {
            address = address.substring(3);
        }
        if (address.startsWith("地") || address.startsWith("址")
                || address.startsWith(":") || address.startsWith("*")) {
            address = address.substring(1);
        }
        if (address.startsWith("一人有限责任公司(外商投资企业法人独资)")) {
            address = address.substring("一人有限责任公司(外商投资企业法人独资)".length());
        }
        if (address.startsWith("有限责任公司(自然人投资或控股)")) {
            address = address.substring("有限责任公司(自然人投资或控股)".length());
        }
        if (address.endsWith("活动)")) {
            address = address.substring(0, address.lastIndexOf("活动)"));
        }
        if (address.endsWith("。")) {
            address = address.substring(0, address.lastIndexOf("。"));
        }
        if (address.endsWith("(自主申报)")) {
            address = address.substring(0, address.lastIndexOf("(自主申报)"));
        }
        if (address.endsWith("(")) {
            address = address.substring(0, address.lastIndexOf("("));
        }
        if (address.contains("(自行分割)")) {
            address = address.replaceAll("(自行分割)","");
        }
        address = filterFailRecognize(address);
        if (address.indexOf("浙江") > 0) {
            address = address.substring(address.indexOf("浙江"));
        }
        return address;
    }

    /**
     * 营业执照中所有解析失败的字段置空
     * @param srt
     * @return
     */
    public static String filterFailRecognize(String srt) {
        if (Objects.equals(srt, FAIL_RECOGNIZE)) {
            srt = "";
        }
        return srt;
    }

    /**
     * 格式化营业执照的统一社会信用代码
     * @param uniCode
     * @return
     */
    public static String formatUnicode(String uniCode) {
        if (StringUtils.isBlank(uniCode)) {
            return "";
        }
        if (uniCode.contains("新氧APP")) {
            uniCode = uniCode.replaceAll("新氧APP", "");
        }
        //统一社会信用代码的长度为18
        if (uniCode.startsWith("CAR") && uniCode.length() > 18) {
            uniCode = uniCode.substring(3);
        }
        if (uniCode.matches(LicenseAnalysisTask.SPECIAL_SYMBOL)) {
            uniCode = uniCode.replaceAll(LicenseAnalysisTask.SPECIAL_SYMBOL_REPLACE, "");
        }
        if (uniCode.matches(LicenseAnalysisTask.REGEX_CHINESE)) {
            uniCode = uniCode.replaceAll(LicenseAnalysisTask.REGEX_CHINESE_REPLACE, "");
        }
        uniCode = LicenseAnalysisTask.filterFailRecognize(uniCode);
        return uniCode;
    }

    /**
     * 格式化执业许可证的登记号
     * @param regNo
     * @return
     */
    public static String formatPracticeRegNo(String regNo) {
        if (StringUtils.isBlank(regNo)) {
            return "";
        }
        if (regNo.contains("新氧APP")) {
            regNo = regNo.replaceAll("新氧APP", "");
        }
        //登记号长度为22
        if (regNo.startsWith("CAR") && regNo.length() > 22) {
            regNo = regNo.substring(3);
        }
        if (regNo.matches(LicenseAnalysisTask.SPECIAL_SYMBOL)) {
            regNo = regNo.replaceAll(LicenseAnalysisTask.SPECIAL_SYMBOL_REPLACE, "");
        }
        if (regNo.matches(LicenseAnalysisTask.REGEX_CHINESE)) {
            regNo = regNo.replaceAll(LicenseAnalysisTask.REGEX_CHINESE_REPLACE, "");
        }
        //如果分号出现的次数大于2，则认为识别失败
        String[] split = regNo.split(";");
        if (split.length > 3) {
            return "";
        }
        regNo = LicenseAnalysisTask.filterFailRecognize(regNo);
        return regNo;
    }

    public static String formatInstitutionName(String institutionName) {
        if (StringUtils.isBlank(institutionName)) {
            return "";
        }
        if (LicenseAnalysisTask.FAIL_RECOGNIZE.equals(institutionName)) {
            return "";
        }
        if (institutionName.matches(INSTITUTION_NAME_SYMBOL)) {
            institutionName = institutionName.replaceAll(INSTITUTION_NAME_SYMBOL_REPLACE, "");
        }
        if (institutionName.matches(DIGITAL_EXP)) {
            institutionName = institutionName.replaceAll(DIGITAL_EXP_REPLACE, "");

        }
        return institutionName;
    }

    public static String formatPersonName(String personName) {
        if (StringUtils.isBlank(personName)) {
            return "";
        }
        if (LicenseAnalysisTask.FAIL_RECOGNIZE.equals(personName)) {
           return "";
        }
        if (personName.matches(SPECIAL_SYMBOL)) {
            personName = personName.replaceAll(SPECIAL_SYMBOL_REPLACE, "");
        }
        if (personName.matches(DIGITAL_EXP)) {
            personName = personName.replaceAll(DIGITAL_EXP_REPLACE, "");
        }
        if (personName.startsWith("址")) {
            personName = personName.substring(1);
        }
        if (personName.startsWith("责人")) {
            personName = personName.substring(2).trim();
        }
        if (personName.matches(PERSON_NAME_FEATURE_WORD)) {
            personName = personName.replaceAll(PERSON_NAME_FEATURE_WORD_REPLACE, "");
        }
        return personName;
    }

    public static String PERSON_NAME_FEATURE_WORD_REPLACE = "[动氧APD|新氧APC|商品名|新氧APD|新氧APP|新氧A|动氧AP]";

    public static String PERSON_NAME_FEATURE_WORD = ".*[动氧APD|新氧APC|商品名|新氧APD|新氧APP|新氧A|动氧AP].*";

}
